package Net::Coro::ProxyPool;
use common::sense;
our $VERSION = 0.01;

use Coro::AnyEvent;

our %singletons;
our $PERIOD = 60*5;

sub new {
	my ($class, $param) = @_;
	return $singletons{$param} if exists $singletons{$param};
	
	my $this = {};
	bless $this, $class;
	
	my ($file, $period, $count) = $param =~ /^(.*?):(\d+)(?::(\d+))?/;
	$file = $param if !$file;
	$this->{_PERIOD} = $period || 0;
	$this->{_COUNT} = $count || !!$period || 0;
	$this->{_INDEX} = 0;
	
	$this->{_AR_GOOD}=[];
	$this->{_HR_GOOD}={};
	$this->{_HR_BAN}={};
	
	$this->{_FILE} = $file;
	while (!$this->init()) {
		warn "can't read proxy file ".$file;
		sleep 1;
	}
	
	$this->{_TIME} = time;
	
	$singletons{$param} = $this;
	return $this;
}

# read sock from file to array;
# 1 - success
sub init {
	my ($this) = @_;
	
	my $time = time;
	foreach (keys %{$this->{_HR_BAN}}) {
		if ($this->{_HR_BAN}->{$_} - $time <= 0) {
			delete $this->{_HR_BAN}->{$_};
		}
	}
	
	return 0 if !open(SCK, "<".$this->{_FILE});
		
	my @socks_tmp = <SCK>;
	close SCK;
	if (!@socks_tmp) {
		return 0;
	} else {
		
		#@good_hash{@socks_tmp} = (1) x @socks_tmp;
		my %tmp_good;
		foreach (@socks_tmp) {
			s/(^\s+|\s+$)//sg;
			next if !$_;
			next if $this->{_HR_BAN}->{$_};
			$tmp_good{$_} =  $this->{_HR_GOOD}->{$_} || 0;
		}
		$this->{_HR_GOOD} = \%tmp_good;
		$this->{_AR_GOOD} = [keys %tmp_good];
		
		return 1;
	}
}

sub get {
	my ($this) = @_;
	
	# timer - init
	if ((my $period = time - $this->{_TIME}) > $PERIOD) {
		$this->{_TIME} += $period if ($this->init);
	}
	
	while (!exists $this->{_AR_GOOD}->[0]) {
		$this->init;
		if (!exists $this->{_AR_GOOD}->[0]) {
			warn "no more proxies, wait ".int($PERIOD/2)." sec\n";
			Coro::AnyEvent::sleep int($PERIOD/2);
		}
	}
	
	# create socks object
	$this->{_INDEX} = 0 if $this->{_INDEX} > $#{$this->{_AR_GOOD}};
	my $str = $this->{_AR_GOOD}->[$this->{_INDEX}++];
	my ($socks_ip, $socks_port) = $str =~ /^([^:]+):(\d+)/s;
	die ("can't find valid proxy adress (need 'host:port' instead '$str') in file $this->{_FILE}. ") if !$socks_port;
	$this->_ban($socks_ip, $socks_port) if ($this->{_COUNT} and ($this->{_HR_GOOD}->{"$socks_ip:$socks_port"}++) >= $this->{_COUNT});
	return ($socks_ip, $socks_port);
}

sub isban {
	my ($this, $socks) = @_;
	my ($ip, $port) = $socks->address;
	return exists $this->{_HR_BAN}->{"$ip:$port"};
}

sub ban {
	my ($this, $socks) = @_;
	my ($ip, $port) = $socks->address;
	$this->_ban($ip, $port);
}
sub _ban {
	my ($this, $ip, $port) = @_;
	return if !$ip;	
	$this->{_HR_BAN}->{"$ip:$port"} = $this->{_PERIOD} + time();
	delete $this->{_HR_GOOD}->{"$ip:$port"};
	$this->{_AR_GOOD} = [keys %{$this->{_HR_GOOD}}];
}

sub free {}
1;
